/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package moteur;

import controlleur.ControllerGrille;
import java.util.Date;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import jreversi.Config;
import jreversi.Coordonnee;

/**
 *
 * @author Jean
 */
public class IA
{

    public IA()
    {
    }

    public Coordonnee jouer(int profondeur)
    {
        Coordonnee meilleur_Coup = null;
        int max_val = Integer.MIN_VALUE;
        ControllerGrille cg = new ControllerGrille();
        ArrayList<Coordonnee> cases = cg.rechercheCoups();

        int alpha = Integer.MIN_VALUE;
        int beta = Integer.MAX_VALUE;

        int val = Integer.MIN_VALUE;

        for (Coordonnee c : cases)
        {
            try
            {
                Plateau p = Plateau.getInstance().clone();
                p.saveTab();
                cg.coupPossible(c.getX(), c.getY());
                p.poseFakePion(c.getX(), c.getY(), cg.getCasesAFlip());
                Plateau p2 = p.clone();
                val = Math.max(val, alpha(p2, profondeur - 1, alpha, beta));
                p.restoreTab();
                if (val < beta)
                {
                    if (val > max_val)
                    {
                        max_val = val;
                        meilleur_Coup = c;
                    }
                    alpha = Math.max(alpha, val);
                }
            }
            catch (CloneNotSupportedException ex)
            {
                Logger.getLogger(IA.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return meilleur_Coup;
    }

    private int eval(Plateau plat)
    {
        char[][] tab = plat.getTabPlateau();
        int score = 0;
        int scoreCoin = 0;
        int nbBlanc = 0;
        int nbNoir = 0;

        int nbCoup = 0;



        ControllerGrille cg = new ControllerGrille(plat);
        boolean jeuFinish = cg.jeuFini();

        for (int i = 0; i < tab.length; i++)
        {
            for (int j = 0; j < tab[0].length; j++)
            {

                if (i == 0 || i == 7 || j == 7 || j == 0)
                {
                    if (i == j || (i == 0 && j == 7) || (j == 0 && i == 7))
                    {
                        scoreCoin += multiplicateur(plat, i, j) * Config.ptsCoin;
                    }
                    else
                    {
                        scoreCoin += multiplicateur(plat, i, j) * Config.ptsBords;
                    }
                }

                if (tab[i][j] == 'b')
                {
                    nbBlanc++;
                }
                else if (tab[i][j] == 'n')
                {
                    nbNoir++;
                }

                if (!jeuFinish && cg.coupPossible(i, j))
                {
                    nbCoup++;
                }
            }
        }

        char c = plat.aQui('n');
        if (c == 'C')
        {
            if (nbNoir > nbBlanc)
            {
                score += Config.ptsDiffPion;
            }
            else
            {
                score -= Config.ptsDiffPion;
            }
        }
        else
        {
            if (nbNoir > nbBlanc)
            {
                score -= Config.ptsDiffPion;
            }
            else
            {
                score += Config.ptsDiffPion;
            }
        }

        score += nbCoup;
        score += scoreCoin;

        return score;
    }

    /**
     * Sert a savoir si je dois multiplier le score par 1 ou -1 
     * afin de donner le score a J1 ou J2
     * @return int valeur égal à 1 ou 0 ou -1.
     */
    private int multiplicateur(Plateau plat, int x, int y)
    {
        int multi = 0;
        char pion = plat.aQui(plat.getTabPlateau()[x][y]);
        // Si le pion appartient a 'C'omputer le score est positif
        if (pion == 'C')
        {
            multi = 1;
        }
        //Si il est vide aucun gain possible
        else if (pion == 'E')
        {
            multi = 0;
        }
        //Sinon negatif
        else
        {
            multi = -1;
        }
        return multi;
    }

    private int min(Plateau clone, int profondeur)
    {
        int min_val = Integer.MAX_VALUE;
        ControllerGrille cg = new ControllerGrille(clone);

        if (cg.jeuFini() || profondeur <= 0)
        {
            min_val = eval(clone);
        }
        else
        {
            ArrayList<Coordonnee> cases = cg.rechercheCoups();

            for (Coordonnee c : cases)
            {
                try
                {
                    clone.saveTab();
                    cg.coupPossible(c.getX(), c.getY());
                    clone.poseFakePion(c.getX(), c.getY(), cg.getCasesAFlip());

                    int val = max(clone.clone(), (profondeur - 1));
                    if (val < min_val)
                    {
                        min_val = val;
                    }
                    clone.restoreTab();
                }
                catch (CloneNotSupportedException ex)
                {
                    Logger.getLogger(IA.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        return min_val;
    }

    private int max(Plateau clone, int profondeur)
    {
        int max_val = Integer.MIN_VALUE;
        ControllerGrille cg = new ControllerGrille(clone);

        if (cg.jeuFini() || profondeur <= 0)
        {
            max_val = eval(clone);
        }
        else
        {
            ArrayList<Coordonnee> cases = cg.rechercheCoups();

            for (Coordonnee c : cases)
            {
                try
                {
                    clone.saveTab();
                    cg.coupPossible(c.getX(), c.getY());
                    clone.poseFakePion(c.getX(), c.getY(), cg.getCasesAFlip());

                    int val = min(clone.clone(), (profondeur - 1));
                    if (val > max_val)
                    {
                        max_val = val;
                    }
                    clone.restoreTab();
                }
                catch (CloneNotSupportedException ex)
                {
                    Logger.getLogger(IA.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        return max_val;
    }

    private int alpha(Plateau clone, int profondeur, int a, int b)
    {
        int val = Integer.MAX_VALUE;
        int alpha = a;
        int beta = b;
        ControllerGrille cg = new ControllerGrille(clone);

        if (cg.jeuFini() || profondeur <= 0)
        {
            val = eval(clone);
        }
        else
        {
            ArrayList<Coordonnee> cases = cg.rechercheCoups();

            for (Coordonnee c : cases)
            {
                try
                {
                    clone.saveTab();
                    cg.coupPossible(c.getX(), c.getY());
                    clone.poseFakePion(c.getX(), c.getY(), cg.getCasesAFlip());

                    val = Math.min(val, beta(clone.clone(), profondeur - 1, alpha, beta));
                    clone.restoreTab();

                    if (alpha < val)
                    {
                        beta = Math.min(beta, val);
                    }
                    else
                    {
                        return val;
                    }

                }
                catch (CloneNotSupportedException ex)
                {
                    Logger.getLogger(IA.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        return val;
    }

    private int beta(Plateau clone, int profondeur, int a, int b)
    {
        int val = Integer.MIN_VALUE;
        int alpha = a;
        int beta = b;
        ControllerGrille cg = new ControllerGrille(clone);

        if (cg.jeuFini() || profondeur <= 0)
        {
            val = eval(clone);
        }
        else
        {
            ArrayList<Coordonnee> cases = cg.rechercheCoups();

            for (Coordonnee c : cases)
            {
                try
                {
                    clone.saveTab();
                    cg.coupPossible(c.getX(), c.getY());
                    clone.poseFakePion(c.getX(), c.getY(), cg.getCasesAFlip());

                    val = Math.max(val, alpha(clone.clone(), profondeur - 1, alpha, beta));
                    clone.restoreTab();
                    if (val < beta)
                    {
                        alpha = Math.max(alpha, val);
                    }
                    else
                    {
                        return val;
                    }
                }
                catch (CloneNotSupportedException ex)
                {
                    Logger.getLogger(IA.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        return val;
    }
}
